#include "app_message.h"
#include <stdlib.h>
#include <string.h>
#include "thirdparty/log/log.h"
#include "thirdparty/cJSON/cJSON.h"

int app_message_strToBinary(char *str, void **ptr, int *len)
{
    int str_len = strlen(str);
    if (str_len % 2 != 0)
    {
        log_warn("Hex string not valid");
        return -1;
    }
    *len = str_len / 2;
    *ptr = malloc(*len);
    if (!*ptr)
    {
        log_warn("Not enough memory for message");
        return -1;
    }

    for (int i = 0; i < str_len; i += 2)
    {
        unsigned char temp = 0;
        if (str[i] >= '0' && str[i] <= '9')
        {
            temp += str[i] - '0';
        }
        else if (str[i] >= 'A' && str[i] <= 'F')
        {
            temp += str[i] - 'A' + 10;
        }
        else
        {
            temp += str[i] - 'a' + 10;
        }
        temp <<= 4;
        if (str[i + 1] >= '0' && str[i + 1] <= '9')
        {
            temp += str[i + 1] - '0';
        }
        else if (str[i + 1] >= 'A' && str[i + 1] <= 'F')
        {
            temp += str[i + 1] - 'A' + 10;
        }
        else
        {
            temp += str[i + 1] - 'a' + 10;
        }
        memcpy(*ptr + i / 2, &temp, 1);
    }

    return 0;
}

char *app_message_binaryToStr(void *ptr, int len)
{
    char table[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    char *str = malloc(len * 2 + 1);
    if (!str)
    {
        return NULL;
    }

    unsigned char *temp = ptr;
    for (int i = 0; i < len; i++)
    {
        // 如果拿到0x0A, 先处理A
        str[i * 2] = table[(temp[i] & 0xF0) >> 4];
        str[i * 2 + 1] = table[temp[i] & 0x0F];
    }

    str[len * 2] = '\0';

    return str;
}
int app_message_initByJson(Message *message, char *json, int len)
{
    // 传入的json格式为：{"connection_type":1,"id":"AABB", "msg":"AABBCCDDEEFF"}
    memset(message, 0, sizeof(Message));
    cJSON *json_obj = cJSON_ParseWithLength(json, len);
    if (!json_obj)
    {
        log_warn("Parse json failed");
        goto JSON_PARSE_FAIL;
    }

    // 解析Connection type
    cJSON *connection_type_json = cJSON_GetObjectItem(json_obj, "connection_type");
    if (!connection_type_json)
    {
        log_warn("Connection_Type parse failed");
        goto MEMBER_PARSE_FAIL;
    }

    message->connection_type = connection_type_json->valueint;

    // 解析id
    cJSON *id_json = cJSON_GetObjectItem(json_obj, "id");
    if (!id_json)
    {
        log_warn("Id parse failed");
        goto MEMBER_PARSE_FAIL;
    }

    cJSON *msg_json = cJSON_GetObjectItem(json_obj, "msg");
    if (!msg_json)
    {
        log_warn("Message parse failed");
        goto MEMBER_PARSE_FAIL;
    }

    void *id_ptr;
    if (app_message_strToBinary(id_json->valuestring, &id_ptr, &message->id_len) < 0)
    {
        log_warn("Id parse failed");
        goto MEMBER_PARSE_FAIL;
    }

    void *message_ptr;
    if (app_message_strToBinary(msg_json->valuestring, &message_ptr, &message->msg_len) < 0)
    {
        log_warn("Message parse failed");
        goto MESSAGE_PARSE_FAIL;
    }

    message->ptr = malloc(message->id_len + message->msg_len);
    if (!message->ptr)
    {
        log_warn("Not enough memory for message");
        goto MALLOC_FAIL;
    }

    memcpy(message->ptr, id_ptr, message->id_len);
    memcpy(message->ptr + message->id_len, message_ptr, message->msg_len);
    free(message_ptr);
    free(id_ptr);
    cJSON_Delete(json_obj);

    return 0;

MALLOC_FAIL:
    free(message_ptr);
MESSAGE_PARSE_FAIL:
    free(id_ptr);
MEMBER_PARSE_FAIL:
    cJSON_Delete(json_obj);
JSON_PARSE_FAIL:
    return -1;
}

int app_message_initByBinary(Message *message, void *ptr, int len)
{
    // 传入的二进制格式为：1type 2 id_len 3 msg_len xxxxxx
    if (len < 3)
    {
        return -1;
    }

    memset(message, 0, sizeof(Message));
    memcpy(&message->connection_type, ptr, 1);
    memcpy(&message->id_len, ptr + 1, 1);
    memcpy(&message->msg_len, ptr + 2, 1);
    if (len != message->id_len + message->msg_len + 3)
    {
        return -1;
    }


    message->ptr = malloc(message->id_len + message->msg_len);
    if (!message->ptr)
    {
        log_warn("Not enough memory for message");
        return -1;
    }
    memcpy(message->ptr, ptr + 3, message->id_len + message->msg_len);

    log_trace("message init by binary success");
    return 0;
}

int app_message_toJson(Message *message, char *json, int len)
{
    // 将Message转化为Json string
    cJSON *json_obj = cJSON_CreateObject();
    if (!json_obj)
    {
        log_warn("Create json object failed");
        return -1;
    }

    cJSON_AddNumberToObject(json_obj, "connection_type", message->connection_type);
    cJSON_AddStringToObject(json_obj, "id", app_message_binaryToStr(message->ptr, message->id_len));
    cJSON_AddStringToObject(json_obj, "msg", app_message_binaryToStr(message->ptr + message->id_len, message->msg_len));

    char *json_str = cJSON_PrintUnformatted(json_obj);
    cJSON_Delete(json_obj);

    if ((int)strlen(json_str) + 1 > len)
    {
        free(json_str);
        log_warn("Json str buf not enough");
        return -1;
    }

    strcpy(json, json_str);
    free(json_str);
    return 0;
}

int app_message_toBinary(Message *message, void *ptr, int len)
{
    if (message->id_len + message->msg_len + 3 > len)
    {
        log_warn("Ptr buffer not enough for message");
        return -1;
    }
    memcpy(ptr, &message->connection_type, 1);
    memcpy(ptr + 1, &message->id_len, 1);
    memcpy(ptr + 2, &message->msg_len, 1);
    memcpy(ptr + 3, message->ptr, message->id_len + message->msg_len);

    return message->id_len + message->msg_len + 3;
}

void app_message_free(Message *message)
{
    free(message->ptr);
}
